﻿// /********************************************************
// *                                                       *
// *   Copyright (C) Microsoft. All rights reserved.       *
// *                                                       *
// ********************************************************/

using TelemetryCommon.TelemetryServiceReference;

namespace TelemetryCommon
{
    using System;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.Linq;
    using System.Reflection;
    using System.Security.Principal;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.ServiceModel.Discovery;
    using System.Threading;

#pragma warning disable 0162

    public static class Snapshot
    {
        private const bool IsTracingAllowed = false;

        private static Mutex s_snapshotMutex;
        private static MarkerClient s_instance;
        private static Mutex s_proxyMutex;

        public static Mutex SnapshotDataMutex
        {
            get { return s_snapshotMutex ?? (s_snapshotMutex = new Mutex()); }
        }

        public static Mutex ProxyMutex
        {
            get { return s_proxyMutex ?? (s_proxyMutex = new Mutex()); }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "ex"), SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public static void DiscoverProxy()
        {
            try
            {
                DiscoveryClient discoveryProcess = new DiscoveryClient(new UdpDiscoveryEndpoint());

                FindCriteria findCriteria = new FindCriteria(typeof(IMarker));
                findCriteria.Duration = new TimeSpan(0, 0, 0, 1, 0);
                findCriteria.MaxResults = 1;

                FindResponse findResponse = discoveryProcess.Find(findCriteria);

                if (findResponse.Endpoints.Any())
                {

                    var endpointDiscoveryMetadata = findResponse.Endpoints.FirstOrDefault();
                    if (endpointDiscoveryMetadata != null)
                    {
                        if (s_instance != null)
                        {
                            s_instance.Abort();
                        }

                        s_instance = new MarkerClient("NetTcpBinding_IMarker");
                    }
                }
            }
            catch (Exception ex)
            {
                if (IsTracingAllowed)
                {
                    //ex.TraceEvent(Tracing.NotificationTrace, "Unable to refresh proxy.");
                }
             }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "ex"), SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        private static MarkerClient Proxy
        {
            get
            {
                if (s_instance == null)
                {
                    try
                    {
                        if (!ProxyMutex.WaitOne(100))
                        {
                            if (IsTracingAllowed)
                            {
//                                Tracing.TraceWarningFromHResult(
//                                    Tracing.NotificationTrace,
//                                    QualityEssentialsErrors.URT_E_QE_AT_SECURITY_INVALID_DOMAIN_ALIAS,
//                                    "Proxy creation timed out (100 ms)");
                            }
                            return null;
                        }

                        if (s_instance == null)
                        {
                            s_instance = new MarkerClient("NetTcpBinding_IMarker");
                        }
                    }
                    catch (Exception ex)
                    {
                        if (IsTracingAllowed)
                        {
//                            ex.TraceEvent(Tracing.NotificationTrace, "Unable to create session.");
                        }
                    }
                    finally
                    {
                        ProxyMutex.ReleaseMutex();
                    }
                }

                return s_instance;
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "ex"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public static void InitiateSession()
        {
            try
            {
                Proxy.InitiateSessionAsync();
            }
            catch (Exception ex)
            {
                if (IsTracingAllowed)
                {
//                    ex.TraceEvent(Tracing.NotificationTrace, "Unable to initiate session.");
                }
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "ex"), SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "ex"), SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public static void CloseSession()
        {
            try
            {
                Proxy.FlushAndCloseSessionAsync();
            }
            catch (Exception ex)
            {
                if (IsTracingAllowed)
                {
//                    ex.TraceEvent(Tracing.NotificationTrace, "Unable to close session.");
                }
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "ex"), SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public static void Generate(params Sensor[] data)
        {
                try
                {
                    Proxy.GenerateSnapshotAsync(SetSharedData(data));
                }
                catch (Exception ex)
                {
                    if (IsTracingAllowed)
                    {
//                        ex.TraceEvent(Tracing.MiscellaneousTrace, "Unable to send telemetry data.");
                    }
                }
        }

        private static MarkerStamp SetSharedData(params Sensor[] data)
        {
            MarkerStamp sData = new MarkerStamp();

            foreach (var snapshotElement in data)
            {
                PropertyInfo piShared = sData.GetType().GetProperty(snapshotElement.ElementName.ToString());
                piShared.SetValue(sData, snapshotElement.ElementValue, null);
            }

            sData.ProcessId = Process.GetCurrentProcess().Id.ToString(CultureInfo.CurrentCulture);
            sData.ProcessName = Process.GetCurrentProcess().ProcessName;

            sData.ThreadNumber = Thread.CurrentThread.ManagedThreadId.ToString(CultureInfo.CurrentCulture);
            sData.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fffffff", CultureInfo.CurrentCulture);

            sData.ComputerName = System.Environment.MachineName;

            sData.ApplicationSession = Process.GetCurrentProcess().SessionId.ToString(CultureInfo.CurrentCulture);

            return sData;
        }
    }
}
